/*
 * DBIterator.java
 *
 * Created on June 5, 2007, 3:34 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.app.db;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Iterator;

/**
 *
 * @author alex
 */
public class DBIterator<T> implements Iterator<T>
{
   
   ResultSet set;
   ResultConstructor<T> constructor;
   DBConnectionPool pool;
   DBConnection connection;
   boolean hasNext = false;
   boolean done = false;
   int start = 1;
   int count = -1;
   
   /** Creates a new instance of DBIterator */
   public DBIterator(ResultSet set,ResultConstructor<T> constructor,DBConnectionPool pool,DBConnection connection)
   {
      this.set = set;
      this.constructor = constructor;
      this.pool = pool;
      this.connection = connection;
      this.start = 1;
      this.count = -1;
   }
   
   public void setStart(int start) {
      this.start = start;
   }

   public void setMaximum(int max) {
      this.count = max;
   }

   protected void ensureAtStart() {
      if (start>1) {
         try {
            while (start>1 && set.next()) {
               start--;
            }
         } catch (SQLException ex) {
            throw new RuntimeException(ex.getMessage(),ex);
         }
      }
      if (start>1) {
         done = true;
      }
   }
   
   public boolean hasNext() {
      if (done) { return false; }
      ensureAtStart();
      if (done) { return false; }
      if (count==0) {
         done = true;
         try {
            finished();
         } catch (SQLException ex) {
            throw new RuntimeException(ex.getMessage(),ex);
         }
         return false;
      }
      if (!hasNext) {
         try {
            hasNext = set.next();
         } catch (SQLException ex) {
            done = true;
            try {
               finished();
            } catch (SQLException inner) {
            }
            throw new RuntimeException(ex.getMessage(),ex);
         }
         if (!hasNext) {
            done = true;
            try {
               finished();
            } catch (SQLException ex) {
               throw new RuntimeException(ex.getMessage(),ex);
            }
         }
      }
      return hasNext;
   }
   public T next() {
      try {
         hasNext = false;
         if (count>0) {
            count--;
         }
         return constructor.newInstance(set);
      } catch (SQLException ex) {
         try {
            finished();
         } catch (SQLException inner) {
         }
         throw new RuntimeException(ex.getMessage(),ex);
      }
   }

   public void remove() {
      throw new UnsupportedOperationException("Cannot remove entries via this iterator.");
   }
   
   public void finished() 
      throws SQLException
   {
      if (connection==null) {
         return;
      }
      Statement statement = set.getStatement();
      set.close();
      if (statement instanceof PreparedStatement) {
         ((PreparedStatement)statement).clearParameters();
      } else {
         statement.close();
      }
      pool.release(connection);
      set = null;
      pool = null;
      connection = null;
   }

   public void finalize() {
      try {
         finished();
      } catch (SQLException ex) {
         throw new RuntimeException(ex.getMessage(),ex);
      }
   }
   
}
